@file:OptIn(
    ExperimentalFoundationApi::class, ExperimentalFoundationApi::class,
    ExperimentalFoundationApi::class
)

package com.lly.markdown

import android.content.Context
import android.util.Log
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CheckBox
import androidx.compose.material.icons.filled.CheckBoxOutlineBlank
import androidx.compose.material.icons.filled.Circle
import androidx.compose.material.icons.filled.ExpandLess
import androidx.compose.material.icons.filled.ExpandMore
import androidx.compose.material.icons.filled.HourglassEmpty
import androidx.compose.material3.Button
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import coil.decode.SvgDecoder
import coil.request.ImageRequest

class MarkdownDataContainer(val list: List<MarkdownData> = emptyList()) {
    override fun equals(other: Any?): Boolean {
        return this === other
    }

    override fun hashCode(): Int {
        return list.hashCode()
    }
}

sealed class MarkdownData(val headingLevels: Int = 1, val index: Int) {
    val isUnfolded = mutableStateOf(true)
    open fun key(): String = index.toString()
}

class HeadingData(val item: Heading, index: Int) : MarkdownData(item.level, index)
class ErrorData(val item: Error, index: Int) : MarkdownData(1, index)

class OtherData(val items: MutableList<MarkdownItem>, headingLevels: Int = 1, index: Int) :
    MarkdownData(headingLevels, index) {
    override fun key(): String = "${index}_${items.size}"
}

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun MarkdownScreen(
    modifier: Modifier,
    markdownData: List<MarkdownData>,
    parentPath: String,
    linkAction: (String) -> Unit
) {
    val context = LocalContext.current
    var showMaxLevel by remember {
        mutableStateOf(3)
    }
    LazyColumn(modifier) {
        item {
            var showSelectDialog by remember {
                mutableStateOf(false)
            }
            DropdownMenu(
                expanded = showSelectDialog,
                onDismissRequest = { showSelectDialog = false }) {
                for (i in 1..7) {
                    DropdownMenuItem(
                        onClick = {
                            showMaxLevel = i
                            showSelectDialog = false
                        },
                        text = { Text(text = "$i 层") }
                    )
                }
            }

            Button(onClick = { showSelectDialog = true }) {
                Text(text = "折叠是最大显示层次:$showMaxLevel \n总的项数:${markdownData.size}")
                Icon(Icons.Default.ExpandMore, contentDescription = "")
            }
        }
        markdownData.forEachIndexed { index, item ->
            when (item) {
                is HeadingData -> {
                    stickyHeader(key = item.key()) {
                        val textStyle = when (item.item.level) {
                            1 -> MaterialTheme.typography.titleLarge

                            2 -> MaterialTheme.typography.titleMedium

                            3 -> MaterialTheme.typography.titleSmall

                            else -> MaterialTheme.typography.titleSmall.let {
                                it.copy(
                                    fontSize = it.fontSize.times(
                                        3.5 / item.item.level
                                    )
                                )
                            }
                        }
                        AnimatedVisibility(visible = item.isUnfolded.value || showMaxLevel >= item.headingLevels) {
                            Surface(
                                color = MaterialTheme.colorScheme.primary,
                                shape = RoundedCornerShape(8.dp),
                                modifier = Modifier
                                    .padding(bottom = 4.dp, start = 8.dp * item.item.level)
                                    .clickable {
                                        val current = !item.isUnfolded.value
                                        val currentLevel = item.headingLevels
                                        for (i in index + 1..<markdownData.size) {
                                            if (markdownData[i].headingLevels > currentLevel) {
                                                markdownData[i].isUnfolded.value = current
                                            } else {
                                                break
                                            }
                                        }
                                        item.isUnfolded.value = current

                                    }
                            ) {
                                Row(verticalAlignment = Alignment.CenterVertically) {
                                    ElementView(
                                        item.item.content, context, textStyle, linkAction,
                                        parentPath, Modifier.padding(8.dp)
                                    )

                                    Icon(
                                        if (item.isUnfolded.value) Icons.Default.ExpandLess else Icons.Default.ExpandMore,
                                        contentDescription = "", modifier = Modifier.padding(4.dp)
                                    )
                                }
                            }
                        }
                    }

                }

                is OtherData -> {
                    item(key = item.key()) {
                        AnimatedVisibility(item.isUnfolded.value) {
                            Column(
                                modifier = Modifier
                                    .padding(start = 8.dp * item.headingLevels)
                                    .padding(vertical = 4.dp)
                            ) {

                                item.items.forEach { item ->
//            Log.e("MarkdownScreen", item.toString())
                                    when (item) {
                                        is Code -> {
                                            SelectionContainer {
                                                Text(
                                                    modifier = Modifier
                                                        .background(MaterialTheme.colorScheme.tertiary)
                                                        .fillMaxWidth(),
                                                    text = item.content,
                                                    style = MaterialTheme.typography.bodySmall.copy(
                                                        color = MaterialTheme.colorScheme.onTertiary
                                                    )
                                                )
                                            }
                                        }

                                        is MList -> {
                                            ListView(
                                                item.items,
                                                parentPath,
                                                linkAction,
                                                item.isOrder
                                            )
                                        }

                                        is MCheckableList -> {
                                            CheckableListView(
                                                item.items,
                                                parentPath,
                                                linkAction,
                                            )
                                        }

                                        is Text -> {

                                            ElementView(
                                                item.content,
                                                context,
                                                MaterialTheme.typography.bodyMedium,
                                                linkAction,
                                                parentPath
                                            )

                                        }

                                        is Table -> {
                                            TableView(
                                                table = item,
                                                parentPath = parentPath,
                                                linkAction = linkAction
                                            )
                                        }

                                        else -> {
                                            throw Exception("数据转换错误")
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                is ErrorData -> {
                    stickyHeader { Text(text = "解析错误") }
                    item {
                        SelectionContainer {
                            Text(
                                modifier = Modifier.background(MaterialTheme.colorScheme.error),
                                text = item.item.info,
                                style = MaterialTheme.typography.bodySmall.copy(
                                    color = MaterialTheme.colorScheme.onError
                                )
                            )
                        }
                    }

                }
            }
        }
    }
}

@Composable
private fun ElementView(
    content: List<Block>,
    context: Context,
    textStyle: TextStyle,
    linkAction: (String) -> Unit,
    parentPath: String,
    modifier: Modifier = Modifier,
) {
    Column {
        rememberVectorPainter(image = Icons.Default.HourglassEmpty)
        content.toElements().forEach {
            when (it) {
                is ImageElement -> {
                    AsyncImage(
                        modifier = modifier,
                        model = ImageRequest.Builder(context)
                            .data(
                                if (it.link.startsWith("./")) {
                                    parentPath + it.link.replaceFirst("./", "")
                                } else {
                                    it.link
                                }
                            )
                            .decoderFactory(SvgDecoder.Factory())
                            .error(R.drawable.empty)
                            .placeholder(R.drawable.empty)
                            .crossfade(true)
                            .build(),
                        contentDescription = it.alt,
                    )

                }

                Null -> {}
                is TextElement -> {
                    ClickableText(
                        modifier = modifier,
                        text = it.text,
                        style = textStyle,
                        onClick = handLinkClick(
                            annotatedText = it.text,
                            linkAction = linkAction
                        )
                    )
                }
            }
        }
    }
}

@Composable
private fun ListView(
    list: List<MListItem>,
    parentPath: String,
    linkAction: (String) -> Unit,
    isOrder: Boolean
) {
    val context = LocalContext.current
    Column {
        list.forEachIndexed { id, it ->
            Row(
                modifier = Modifier.padding(start = 4.dp * it.indent, bottom = 4.dp),
                verticalAlignment = Alignment.CenterVertically
            ) {
                if (isOrder) {
                    Text(text = "${id + 1}.\t")
                } else {
                    Icon(
                        Icons.Default.Circle,
                        contentDescription = "",
                        modifier = Modifier
                            .size(8.dp)
                            .padding(end = 4.dp)
                    )
                }
                OutlinedCard {
                    ElementView(
                        content = it.content,
                        context = context,
                        textStyle = MaterialTheme.typography.bodyMedium,
                        linkAction = linkAction,
                        parentPath = parentPath,
                        Modifier.padding(4.dp)
                    )
                }
            }
            if (it.children.isNotEmpty()) {
                ListView(list = it.children, parentPath, linkAction = linkAction, isOrder)
            }
        }
    }
}

@Composable
private fun CheckableListView(
    list: List<MCheckableListItem>,
    parentPath: String,
    linkAction: (String) -> Unit,
) {
    val context = LocalContext.current
    Column {
        list.forEachIndexed { _, it ->
            Row(
                modifier = Modifier.padding(start = 4.dp * it.indent, bottom = 4.dp),
                verticalAlignment = Alignment.CenterVertically
            ) {
                Icon(
                    imageVector = if (it.isCheckable) Icons.Default.CheckBox else Icons.Default.CheckBoxOutlineBlank,
                    contentDescription = "${it.isCheckable}",
                    modifier = Modifier.padding(
                        start = 4.dp * it.indent
                    ),
                )
                OutlinedCard {
                    ElementView(
                        content = it.content,
                        context = context,
                        textStyle = MaterialTheme.typography.bodyMedium,
                        linkAction = linkAction,
                        parentPath = parentPath,
                        Modifier.padding(4.dp)
                    )
                }
            }
            if (it.children.isNotEmpty()) {
                CheckableListView(list = it.children, parentPath, linkAction = linkAction)
            }
        }
    }
}

@Composable
private fun TableView(table: Table, parentPath: String, linkAction: (String) -> Unit) {
    val context = LocalContext.current
    val textStyle = MaterialTheme.typography.bodyMedium
    val containerColors =
        arrayOf(MaterialTheme.colorScheme.secondaryContainer, MaterialTheme.colorScheme.tertiary)
    LazyVerticalGrid(
        columns = GridCells.Fixed(table.maxColums),
        modifier = Modifier.heightIn(100.dp, 500.dp)
    ) {
        table.rows.forEach { row ->
            row.cells.forEachIndexed { index, it ->
                item {
                    OutlinedCard(
                        colors = CardDefaults.outlinedCardColors()
                            .copy(containerColor = containerColors[index % 2])
                    ) {
                        val contentAlignment: Alignment =
                            when (table.aligns.getOrNull(index) ?: Table.Center) {
                                Table.Left -> Alignment.CenterStart
                                Table.Right -> Alignment.CenterEnd
                                else -> Alignment.Center
                            }
                        Box(
                            modifier = Modifier.fillMaxWidth(),
                            contentAlignment = contentAlignment
                        ) {
                            ElementView(
                                content = it,
                                context = context,
                                textStyle = textStyle,
                                linkAction = linkAction,
                                parentPath = parentPath,
                                Modifier
                                    .padding(4.dp)
                                    .wrapContentWidth()
                            )
                        }
                    }
                }
            }
            for (i in row.cells.size..<table.maxColums) {
                item {
                    Text(text = "")
                }
            }
        }
    }
}

@Composable
private fun handLinkClick(
    annotatedText: AnnotatedString,
    linkAction: (String) -> Unit
): (Int) -> Unit = { offset ->
    // We check if there is an *URL* annotation attached to the text
    // at the clicked position
    annotatedText.getStringAnnotations(
        tag = Block.LINK_TAG, start = offset, end = offset
    ).firstOrNull()?.let { annotation ->
        // If yes, we log its value
        Log.d("Clicked URL", annotation.item)
        linkAction(annotation.item)
    }
}